package toolx

import (
	"context"
	"regexp"
	"strings"

	"gitee.com/chunanyong/zorm"
	"gitee.com/workits/pkgs/dbx"
)

type MySQLTool struct {
	dbCfg dbx.Config
}

func (t *MySQLTool) TableToStructInfo(dbName, tableName, ignorePrefix, structName string, isStandard bool) StructInfo {
	tb := t.getTableInfo(dbName, tableName)
	tbName := tb.Name
	if len(structName) == 0 {
		if len(ignorePrefix) > 0 {
			tbName = tbName[len(ignorePrefix):]
		}
	} else {
		tbName = structName
	}
	tbName = strings.TrimLeft(tbName, "_")

	structInfo := StructInfo{
		Name:       UderscoreToLowerCamelCase(tbName),
		StructName: UderscoreToUpperCamelCase(tbName),
		TableName:  tb.Name,
		FileName:   CamelCaseToUdnderscore(tbName),
		Comment:    tb.Comment,
		IsStandard: isStandard,
	}

	var fields []StructField
	for _, col := range tb.Fields {
		field := StructField{
			FieldName:  UderscoreToUpperCamelCase(col.Field),
			ColumnName: col.Field,
			JsonName:   UderscoreToLowerCamelCase(col.Field),
			Comment:    col.Comment,
		}

		// 是否必填项
		if col.Null == "NO" {
			field.Required = true
		}

		// 默认值
		if isStandard {
			if field.FieldName == "CreatedAt" || field.FieldName == "UpdatedAt" {
				field.Default = "time.Now()"
			}
		} else {
			if len(col.Default) > 0 {
				switch col.Default {
				case "CURRENT_TIMESTAMP":
					field.Default = "time.Now()"
				default:
					field.Default = "\"" + col.Default + "\""
				}
			}
		}

		// 数据类型转换：db -> golang
		typ := strings.ToUpper(col.Type)
		if strings.Index(typ, "TIME") == 0 || strings.Index(typ, "DATE") == 0 {
			field.Type = "time.Time"
			if structInfo.IsStandard {
				if field.FieldName != "CreatedAt" && field.FieldName != "UpdatedAt" && field.FieldName != "DeletedAt" {
					structInfo.HasTime = true
				}
			} else {
				structInfo.HasTime = true
			}
		} else {
			switch typ {
			case "INT", "INTEGER":
				field.Type = "int"
			case "BIGINT":
				field.Type = "int64"
			case "SMALLINT", "MEDIUMINT":
				field.Type = "int32"
			case "FLOAT":
				field.Type = "float32"
			case "DOUBLE", "REAL", "DOUBLE PRECISION":
				field.Type = "float64"
			case "DECIMAL", "NUMBER", "NUMERIC", "DEC":
				field.Type = "decimal.Decimal"
				structInfo.HasDecimal = true
			case "TINYINT":
				field.Type = "int8"
			case "BIT", "BYTE":
				field.Type = "byte"
			case "BLOB":
				field.Type = "[]byte"
			default:
				field.Type = "string"
			}
		}

		// 主健
		if col.Key == "PRI" {
			structInfo.PrimaryKeyColumn = field.ColumnName
			structInfo.PrimaryKeyField = field.FieldName
			structInfo.PrimaryKeyName = field.JsonName
			structInfo.PrimaryKeyType = field.Type
			field.IsPrimaryKey = true
		}

		fields = append(fields, field)
	}
	structInfo.Fields = fields

	return structInfo
}

// 获取表信息
func (t *MySQLTool) getTableInfo(dbName, tableName string) *TableInfoEntity {
	if dbx.GetDefaultDao() == nil {
		if err := dbx.InitConn(t.dbCfg); err != nil {
			panic("🙅数据库初始化失败")
		}
		zorm.FuncPrintSQL = func(ctx context.Context, sqlstr string, args []interface{}, execSQLMillis int64) {}
	}

	ctx := context.Background()

	// 获取表注释
	finder := zorm.NewFinder()
	finder.Append("show table status from").Append(dbName).Append("where name = ?", tableName)
	tb := new(TableInfoEntity)
	if has, err := zorm.QueryRow(ctx, finder, tb); err != nil {
		panic(err)
	} else {
		if !has {
			panic("🙅数据库表不存在")
		}
	}

	// 获取字段信息
	finder = zorm.NewFinder()
	finder.Append("show full columns from").Append(tableName)
	finder.SelectTotalCount = false
	var cols []*ColumnInfoEntity
	if err := zorm.Query(ctx, finder, &cols, nil); err != nil {
		panic(err)
	}
	reg := regexp.MustCompile(`\((.*?)\)`)
	for _, col := range cols {
		// 正则替换类型的长度
		col.Type = reg.ReplaceAllString(col.Type, "")
	}
	tb.Fields = cols

	return tb
}
